package edison.jcr;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Calendar;
import java.util.Iterator;
import java.util.Set;
import javax.jcr.AccessDeniedException;
import javax.jcr.Binary;
import javax.jcr.InvalidItemStateException;
import javax.jcr.InvalidLifecycleTransitionException;
import javax.jcr.Item;
import javax.jcr.ItemExistsException;
import javax.jcr.ItemNotFoundException;
import javax.jcr.MergeException;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Node;
import javax.jcr.NodeIterator;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFormatException;
import javax.jcr.lock.Lock;
import javax.jcr.lock.LockException;
import javax.jcr.nodetype.ConstraintViolationException;
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
import javax.jcr.nodetype.NodeTypeManager;
import javax.jcr.version.ActivityViolationException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
import javax.jcr.version.VersionHistory;

import edison.persistence.Dialect;
import edison.persistence.ItemService;
import edison.persistence.NodeBean;
import edison.persistence.PersistenceException;
import edison.persistence.PropertyBean;
import edison.persistence.ResultIterator;
import edison.utils.Configuration;
import edison.utils.Converter;
import edison.utils.Path;

public class NodeImpl extends ItemImpl implements Node {

	private String identifier;
	private String uuid;
	private String nodeTypeName;
	private Set<String> mixinNodeTypeNames;
	private NodeTypeManager nodeTypeManager;
	private NodeDefinition nodeDefinition;

	public NodeImpl(SessionContext context, String path) throws RepositoryException {
		super(context, path, true);

	}

	public Node addNode(String relPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException {
		//
		// String targetPath = Path.combine(this.getPath(), relPath);
		// String parentPath = Path.getParent(targetPath);
		//
		// try {
		// if (!itemService.itemExists(parentPath)) {
		// throw new PathNotFoundException();
		// }
		//
		// Node node = this.getNode(relPath);
		// if (node != null || itemService.itemExists(targetPath)) {
		// throw new ItemExistsException();
		// }
		//
		// if (true) {
		// throw new VersionException();
		// }
		// if (true) {
		// throw new ConstraintViolationException();
		// }
		// if (true) {
		// throw new LockException();
		// }
		// } catch (PersistenceException e) {
		// throw new RepositoryException(e);
		// }

		return null;
	}

	public Node addNode(String relPath, String primaryNodeTypeName) throws ItemExistsException, PathNotFoundException, NoSuchNodeTypeException, LockException, VersionException, ConstraintViolationException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public void orderBefore(String srcChildRelPath, String destChildRelPath) throws UnsupportedRepositoryOperationException, VersionException, ConstraintViolationException, ItemNotFoundException, LockException, RepositoryException {
		// if
		// (!Boolean.parseBoolean(this.getSession().getRepository().getDescriptor(Repository.NODE_TYPE_MANAGEMENT_ORDERABLE_CHILD_NODES_SUPPORTED)))
		// {
		// throw new UnsupportedRepositoryOperationException();
		// }
		//
		// String srcChildAbsPath = Path.combine(this.getPath(),
		// srcChildRelPath);
		// Node node = this.getNode(srcChildRelPath);
		// try {
		// if (node != null || itemService.itemExists(srcChildAbsPath)) {
		// throw new ItemExistsException();
		// }
		// } catch (PersistenceException e) {
		// throw new RepositoryException(e);
		// }
	}

	public Property setProperty(String name, Value value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Property property = getProperty(name);
		property.setValue(value);
		return property;

	}

	public Property setProperty(String name, Value value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Property property = getProperty(name);
		property.setValue(VALUE_FACTORY.createValue(value.toString(), type));
		return property;
	}

	public Property setProperty(String name, Value[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Property property = getProperty(name);
		property.setValue(values);
		return property;
	}

	public Property setProperty(String name, Value[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {

		Value[] vs = new Value[values.length];
		for (int i = 0; i < values.length; i++) {
			vs[i] = VALUE_FACTORY.createValue(values[i].toString(), type);
		}

		return setProperty(name, vs);
	}

	public Property setProperty(String name, String[] values) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Value[] vs = new Value[values.length];
		for (int i = 0; i < values.length; i++) {
			vs[i] = VALUE_FACTORY.createValue(values[i].toString(), PropertyType.STRING);
		}

		return setProperty(name, vs);
	}

	public Property setProperty(String name, String[] values, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Value[] vs = new Value[values.length];
		for (int i = 0; i < values.length; i++) {
			vs[i] = VALUE_FACTORY.createValue(values[i], type);
		}

		return setProperty(name, vs);
	}

	@SuppressWarnings("deprecation")
	private Property setPropertyObject(String name, Object value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Property property = getProperty(name);
		if (value instanceof String)
			property.setValue((String) value);
		else if (value instanceof InputStream)
			property.setValue((InputStream) value);
		else if (value instanceof Binary)
			property.setValue((Binary) value);
		else if (value instanceof Long)
			property.setValue((Long) value);
		else if (value instanceof Double)
			property.setValue((Double) value);
		else if (value instanceof BigDecimal)
			property.setValue((BigDecimal) value);
		else if (value instanceof Calendar)
			property.setValue((Calendar) value);
		else if (value instanceof Boolean)
			property.setValue((Boolean) value);
		else if (value instanceof Node)
			property.setValue((Node) value);
		return property;

	}

	private Property setPropertyObject(String name, Object value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		Property property = getProperty(name);
		property.setValue(VALUE_FACTORY.createValue(value.toString(), type));
		return property;
	}

	public Property setProperty(String name, String value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, String value, int type) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value, type);
	}

	public Property setProperty(String name, InputStream value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, Binary value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, boolean value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, double value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, BigDecimal value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, long value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, Calendar value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Property setProperty(String name, Node value) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, RepositoryException {
		return setPropertyObject(name, value);
	}

	public Node getNode(String relPath) throws PathNotFoundException, RepositoryException {
		String nodePath = path.relPath(relPath);
		Node node;
		try {
			node = (Node) getItemByPath(nodePath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		if (node == null)
			throw new PathNotFoundException();

		return node;
	}

	public NodeIterator getNodes() throws RepositoryException {
		return getNodes("*");

	}

	public NodeIterator getNodes(String namePattern) throws RepositoryException {
		return getNodes(new String[] { namePattern });
	}

	public NodeIterator getNodes(String[] nameGlobs) throws RepositoryException {
		try {
			return dialect.getChildNodes(context, path.toString(), nameGlobs);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

	}

	public Property getProperty(String relPath) throws PathNotFoundException, RepositoryException {
		String propertyPath = path.relPath(relPath);
		Property property;
		try {
			property = dialect.getProperty(context, propertyPath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		if (property == null)
			throw new PathNotFoundException();

		return property;
	}

	public PropertyIterator getProperties() throws RepositoryException {
		return getProperties("*");
	}

	public PropertyIterator getProperties(String namePattern) throws RepositoryException {
		return getProperties(new String[] { namePattern });
	}

	public PropertyIterator getProperties(String[] nameGlobs) throws RepositoryException {
		try {
			return dialect.getProperties(context, path.toString(), nameGlobs);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}
	}

	public Item getPrimaryItem() throws ItemNotFoundException, RepositoryException {
		NodeType nodeType = nodeTypeManager.getNodeType(nodeTypeName);
		Node d;
		String itemName = nodeType.getPrimaryItemName();
		String itemPath = path.relPath(itemName);
		return null;
	}

	public String getUUID() throws UnsupportedRepositoryOperationException, RepositoryException {
		return uuid;
	}

	public String getIdentifier() throws RepositoryException {
		return identifier;
	}

	public int getIndex() throws RepositoryException {
		return 1;
	}

	public PropertyIterator getReferences() throws RepositoryException {
		ResultIterator iterator;
		try {
			iterator = itemService.getReferenceChildPropertiesByPath(getPath());
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		return new PropertyIteratorImpl(iterator, Property.class);
	}

	public PropertyIterator getReferences(String name) throws RepositoryException {
		ResultIterator iterator;
		try {
			iterator = itemService.getReferenceChildPropertiesByPath(getPath(), name);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		return new PropertyIteratorImpl(iterator, Property.class);
	}

	public PropertyIterator getWeakReferences() throws RepositoryException {
		ResultIterator iterator;
		try {
			iterator = itemService.getWeakReferenceChildPropertiesByPath(getPath());
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		return new PropertyIteratorImpl(iterator, Property.class);
	}

	public PropertyIterator getWeakReferences(String name) throws RepositoryException {
		ResultIterator iterator;
		try {
			iterator = itemService.getWeakReferenceChildPropertiesByPath(getPath(), name);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}

		return new PropertyIteratorImpl(iterator, Property.class);
	}

	public boolean hasNode(String relPath) throws RepositoryException {
		String absPath = Path.relPath(getPath(), relPath);
		try {
			return itemService.childNodeExists(absPath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}
	}

	public boolean hasProperty(String relPath) throws RepositoryException {
		String absPath = Path.relPath(getPath(), relPath);
		try {
			return itemService.childPropertyExists(absPath);
		} catch (PersistenceException e) {
			throw new RepositoryException(e);
		}
	}

	public boolean hasNodes() throws RepositoryException {
		return hasNode("");
	}

	public boolean hasProperties() throws RepositoryException {
		return hasProperty("");
	}

	public NodeType getPrimaryNodeType() throws RepositoryException {
		return nodeTypeManager.getNodeType(nodeTypeName);
	}

	public NodeType[] getMixinNodeTypes() throws RepositoryException {
		NodeType[] mixinNodeTypes = new NodeType[mixinNodeTypeNames.size()];

		int index = 0;
		for (Iterator<String> iterator = mixinNodeTypeNames.iterator(); iterator.hasNext();) {
			String mixinName = iterator.next();
			mixinNodeTypes[index] = nodeTypeManager.getNodeType(mixinName);
			index++;
		}

		return mixinNodeTypes;
	}

	public boolean isNodeType(String nodeTypeName) throws RepositoryException {
		if (this.nodeTypeName.equals(nodeTypeName))
			return true;

		return mixinNodeTypeNames.contains(nodeTypeName);
	}

	public void setPrimaryType(String nodeTypeName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
		if (!nodeTypeManager.hasNodeType(nodeTypeName))
			throw new NoSuchNodeTypeException();

		this.nodeTypeName = nodeTypeName;
	}

	public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
		if (!nodeTypeManager.hasNodeType(mixinName))
			throw new NoSuchNodeTypeException();

		mixinNodeTypeNames.add(mixinName);
	}

	public void removeMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
		mixinNodeTypeNames.remove(mixinName);
	}

	public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException {
		if (!nodeTypeManager.hasNodeType(mixinName))
			throw new NoSuchNodeTypeException();

		return true;
	}

	public NodeDefinition getDefinition() throws RepositoryException {
		return nodeDefinition;
	}

	public Version checkin() throws VersionException, UnsupportedRepositoryOperationException, InvalidItemStateException, LockException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public void checkout() throws UnsupportedRepositoryOperationException, LockException, ActivityViolationException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void doneMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void cancelMerge(Version version) throws VersionException, InvalidItemStateException, UnsupportedRepositoryOperationException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void update(String srcWorkspace) throws NoSuchWorkspaceException, AccessDeniedException, LockException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public NodeIterator merge(String srcWorkspace, boolean bestEffort) throws NoSuchWorkspaceException, AccessDeniedException, MergeException, LockException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public String getCorrespondingNodePath(String workspaceName) throws ItemNotFoundException, NoSuchWorkspaceException, AccessDeniedException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public NodeIterator getSharedSet() throws RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public void removeSharedSet() throws VersionException, LockException, ConstraintViolationException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void removeShare() throws VersionException, LockException, ConstraintViolationException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public boolean isCheckedOut() throws RepositoryException {
		// TODO Auto-generated method stub
		return false;
	}

	public void restore(String versionName, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void restore(Version version, boolean removeExisting) throws VersionException, ItemExistsException, InvalidItemStateException, UnsupportedRepositoryOperationException, LockException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void restore(Version version, String relPath, boolean removeExisting) throws PathNotFoundException, ItemExistsException, VersionException, ConstraintViolationException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public void restoreByLabel(String versionLabel, boolean removeExisting) throws VersionException, ItemExistsException, UnsupportedRepositoryOperationException, LockException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public VersionHistory getVersionHistory() throws UnsupportedRepositoryOperationException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public Version getBaseVersion() throws UnsupportedRepositoryOperationException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public Lock lock(boolean isDeep, boolean isSessionScoped) throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public Lock getLock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, RepositoryException {
		// TODO Auto-generated method stub
		return null;
	}

	public void unlock() throws UnsupportedRepositoryOperationException, LockException, AccessDeniedException, InvalidItemStateException, RepositoryException {
		// TODO Auto-generated method stub

	}

	public boolean holdsLock() throws RepositoryException {
		// TODO Auto-generated method stub
		return false;
	}

	public boolean isLocked() throws RepositoryException {
		// TODO Auto-generated method stub
		return false;
	}

	public void followLifecycleTransition(String transition) throws UnsupportedRepositoryOperationException, InvalidLifecycleTransitionException, RepositoryException {
		throw new UnsupportedRepositoryOperationException();

	}

	public String[] getAllowedLifecycleTransistions() throws UnsupportedRepositoryOperationException, RepositoryException {
		throw new UnsupportedRepositoryOperationException();
	}

	@Override
	protected Item getItemByPath(String path) {
		// TODO Auto-generated method stub
		return null;
	}

}